using System;
using NUnit.Framework;
using dnA.Math;
using dnA.Exceptions;

namespace dnA.dnAtests.Math {
	[TestFixture]
	public class ComplexFloatSVDDecompTest {
		private static ComplexFloatSVDDecomp svd;
		private static ComplexFloatSVDDecomp lsvd;
		private static ComplexFloatSVDDecomp wsvd;
		private static bool first = true;
		private const float TOLERENCE = 0.01f;

		[TestFixtureSetUp]
		public void Init(){
			if( first ){
				ComplexFloatMatrix a = new ComplexFloatMatrix(3);
				a[0,0] = new ComplexFloat(1.1f, 1.1f);
				a[0,1] = new ComplexFloat(2.2f, -2.2f);
				a[0,2] = new ComplexFloat(3.3f, 3.3f);
				a[1,0] = new ComplexFloat(4.4f, -4.4f);
				a[1,1] = new ComplexFloat(5.5f, 5.5f);
				a[1,2] = new ComplexFloat(6.6f, -6.6f);
				a[2,0] = new ComplexFloat(7.7f, 7.7f);
				a[2,1] = new ComplexFloat(8.8f, -8.8f);
				a[2,2] = new ComplexFloat(9.9f, 9.9f);
				svd = new ComplexFloatSVDDecomp(a);
			
				a = new ComplexFloatMatrix(2,4);
				a[0,0] = new ComplexFloat(1.1f, 1.1f);
				a[0,1] = new ComplexFloat(2.2f, -2.2f);
				a[0,2] = new ComplexFloat(3.3f, 3.3f);
				a[0,3] = new ComplexFloat(4.4f, -4.4f);
				a[1,0] = new ComplexFloat(5.5f, 5.5f);
				a[1,1] = new ComplexFloat(6.6f, -6.6f);
				a[1,2] = new ComplexFloat(7.7f, 7.7f);
				a[1,3] = new ComplexFloat(8.8f, -8.8f);

				wsvd = new ComplexFloatSVDDecomp(a);
				
				a = new ComplexFloatMatrix(4,2);
				a[0,0] = new ComplexFloat(1.1f, 1.1f);
				a[0,1] = new ComplexFloat(2.2f, -2.2f);
				a[1,0] = new ComplexFloat(3.3f, 3.3f);
				a[1,1] = new ComplexFloat(4.4f, -4.4f);
				a[2,0] = new ComplexFloat(5.5f, 5.5f);
				a[2,1] = new ComplexFloat(6.6f, -6.6f);
				a[3,0] = new ComplexFloat(7.7f, 7.7f);
				a[3,1] = new ComplexFloat(8.8f, -8.8f);
				
				lsvd = new ComplexFloatSVDDecomp(a);
				first = false;
			}
		}

/*		[Test]
		public void UTest(){
			Assert.AreEqual(svd.U.ColumnLength,3);
			Assert.AreEqual(svd.U.RowLength,3);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Real),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,0].Real),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Real),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,2].Real),0.69,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,0].Real),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,1].Real),0.68,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,2].Real),0.01,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,0].Real),0.65,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,1].Real),0.20,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,2].Real),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,0].Imag),0.17,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1].Imag),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,2].Imag),0.69,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,0].Imag),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,1].Imag),0.68,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,2].Imag),0.01,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,0].Imag),0.65,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,1].Imag),0.20,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,2].Imag),0.17,TOLERENCE);		
		}

		[Test]
		public void VTest(){
			Assert.AreEqual(svd.V.ColumnLength,3);
			Assert.AreEqual(svd.V.RowLength,3);
			Assert.AreEqual(System.Math.Abs(svd.V[0,0].Real),0.531,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,1].Real),0.221,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,2].Real),0.818,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,0].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,1].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,2].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,0].Real),0.728,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,1].Real),0.375,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,2].Real),0.574,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,2].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,0].Imag),0.43,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,1].Imag),0.90,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,2].Imag),0.04,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,2].Imag),0,TOLERENCE);		
			}
*/
		[Test]
		public void STest(){
			Assert.AreEqual(svd.S[0,0],23.088,TOLERENCE);
			Assert.AreEqual(svd.S[1,1],12.417,TOLERENCE);
			Assert.AreEqual(svd.S[2,2],1.576,TOLERENCE);
		}

/*		[Test]
		public void LUTest(){
			Assert.AreEqual(lsvd.U.ColumnLength,2);
			Assert.AreEqual(lsvd.U.RowLength,4);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,0].Real),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,1].Real),0.58,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,2].Real),0.37,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,3].Real),0.34,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,0].Real),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,1].Real),0.30,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,2].Real),0.21,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,3].Real),0.75,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,0].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,1].Real),0.01,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,2].Real),0.68,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,3].Real),0.49,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,0].Real),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,1].Real),0.27,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,2].Real),0.52,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,3].Real),0.08,TOLERENCE);

			Assert.AreEqual(System.Math.Abs(lsvd.U[0,0].Imag),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,1].Imag),0.58,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,2].Imag),0.16,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[0,3].Imag),0.16,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,0].Imag),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,1].Imag),0.30,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,2].Imag),0.24,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[1,3].Imag),0.21,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,0].Imag),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,1].Imag),0.01,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,2].Imag),0.02,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[2,3].Imag),0.07,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,0].Imag),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,1].Imag),0.27,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,2].Imag),0.09,TOLERENCE);
//			Assert.AreEqual(System.Math.Abs(lsvd.U[3,3].Imag),0.12,TOLERENCE);
		}

		[Test]
		public void LVTest(){
			Assert.AreEqual(lsvd.V.ColumnLength,2);
			Assert.AreEqual(lsvd.V.RowLength,2);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,0].Real),0.641,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,1].Real),0.767,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,0].Real),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,1].Real),0,TOLERENCE);		
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,0].Imag),0.77,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,1].Imag),0.64,TOLERENCE);			
		}
*/		
		[Test]
		public void LSTest(){
			Assert.AreEqual(lsvd.S[0,0],22.198,TOLERENCE);
			Assert.AreEqual(lsvd.S[1,1],0.975,TOLERENCE);
		}

/*		[Test]
		public void WUTest(){
			Assert.AreEqual(wsvd.U.ColumnLength,2);
			Assert.AreEqual(wsvd.U.RowLength,2);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,0].Real),0.376,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,1].Real),0.927,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,0].Real),0.927,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,1].Real),0.376,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,1].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,0].Imag),0,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,1].Imag),0,TOLERENCE);
		}

		[Test]
		public void WVTest(){
			Assert.AreEqual(wsvd.V.ColumnLength,4);
			Assert.AreEqual(wsvd.V.RowLength,4);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,0].Real),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,1].Real),0.54,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,2].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,3].Real),0.11,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,0].Real),0.31,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,1].Real),0.23,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,2].Real),0.19,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,3].Real),0.77,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,0].Real),0.38,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,1].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,2].Real),0.67,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,3].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,0].Real),0.44,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,1].Real),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,2].Real),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,3].Real),0.07,TOLERENCE);

			Assert.AreEqual(System.Math.Abs(wsvd.V[0,0].Imag),0.25,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,1].Imag),0.54,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,2].Imag),0.14,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,3].Imag),0.35,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,0].Imag),0.31,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,1].Imag),0.23,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,2].Imag),0.24,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,3].Imag),0.12,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,0].Imag),0.38,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,1].Imag),0.08,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,2].Imag),0.03,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,3].Imag),0.49,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,0].Imag),0.44,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,1].Imag),0.39,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,2].Imag),0.53,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,3].Imag),0.09,TOLERENCE);
		}
*/		
		[Test]
		public void WSTest(){
			Assert.AreEqual(System.Math.Abs(wsvd.S[0,0]),22.132,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.S[1,1]),1.956,TOLERENCE);
		}
		
		[Test]
		public void RankTest(){
			Assert.AreEqual(svd.Rank,3);
		}		

		[Test]
		public void ConditionTest(){
			Assert.AreEqual(svd.Condition,14.650,TOLERENCE);
		}		

		[Test]
		public void NormTest(){
			Assert.AreEqual(svd.Norm2,23.088,TOLERENCE);
		}		
		
		[Test]
		public void LRankTest(){
			Assert.AreEqual(lsvd.Rank,2);
		}
		
		[Test]
		public void LConditionTest(){
			Assert.AreEqual(lsvd.Condition,22.764,TOLERENCE);
		}
		
		[Test]
		public void LNormTest(){
			Assert.AreEqual(lsvd.Norm2,22.198,TOLERENCE);
		}

		[Test]
		public void WRankTest(){
			Assert.AreEqual(wsvd.Rank,2);
		}
		
		[Test]
		public void WConditionTest(){
			Assert.AreEqual(wsvd.Condition,11.316,TOLERENCE);
		}
		
		[Test]
		public void WNormTest(){
			Assert.AreEqual(wsvd.Norm2,22.133,TOLERENCE);
		}
	}
}

